﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;
using System.IO;

using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.SdkTypeProxy.Metadata;

namespace TransactionServer.CRMPlugin.CRM
{
    public enum uds_eventtypecode
    {
        Create = 752560000,
        Update = 752560001,
        Delete = 752560002,
        Assign = 752560003
    }

    public class GenerateEventFromCRM : IPlugin
    {
        private string secureConfiguration;
        private string unsecureConfiguration;
        public Dictionary<string, object> Connector;
        XmlSerializer serializer = new XmlSerializer(typeof(Event));

        private string system;
        private string user;

        private AttributeMetadata getAttrByName(EntityMetadata emd, string attrName)
        {
            AttributeMetadata result = null;

            foreach (AttributeMetadata amd in emd.Attributes)
            {
                if (amd.LogicalName == attrName)
                {
                    result = amd;
                }
            }

            return result;
        }

        public GenerateEventFromCRM(string unsecureConfiguration, string secureConfiguration)
        {
            this.secureConfiguration = secureConfiguration;
            this.unsecureConfiguration = unsecureConfiguration;

            if (!String.IsNullOrEmpty(unsecureConfiguration))
            {
                try
                {
                    var strings = unsecureConfiguration.Split(';');
                    system = strings[0];
                    if (strings.Length >= 2)
                    {
                        user = strings[1];
                    }
                }
                catch
                {
                    system = unsecureConfiguration;
                }
            }
        }

        public void Execute(IPluginExecutionContext context)
        {
            ICrmService service = context.CreateCrmService(true);
            IMetadataService mService = context.CreateMetadataService(true);

            if (!String.IsNullOrEmpty(user) && context.InitiatingUserId.Equals(new Guid(user)))
                return;

            DynamicEntity de = null;
            Guid id = Guid.Empty;
            Moniker mon = null;

            RetrieveEntityRequest rerq = new RetrieveEntityRequest();
            rerq.EntityItems =EntityItems.IncludeAttributes | EntityItems.IncludeRelationships;
            rerq.LogicalName = context.PrimaryEntityName;

            EntityMetadata emd = ((RetrieveEntityResponse)mService.Execute(rerq)).EntityMetadata;

            uds_eventtypecode code;

            if (context.MessageName == "Create")
            {
                de = (DynamicEntity)context.PostEntityImages["Image"];
                id = (Guid)context.OutputParameters["id"];

                code = uds_eventtypecode.Create;
            }
            else if (context.MessageName == "Update")
            {
                de = (DynamicEntity)context.PostEntityImages["Image"];
                id = ((Key)de.Properties[emd.PrimaryKey]).Value;

                code = uds_eventtypecode.Update;
            }
            else if (context.MessageName == "Delete")
            {
                mon = context.InputParameters.Properties["Target"] as Moniker;
                de = new DynamicEntity();
                de.Name = mon.Name;
                id = mon.Id;

                code = uds_eventtypecode.Delete;
            }
            else if (context.MessageName == "Assign")
            {
                mon = context.InputParameters.Properties["Target"] as Moniker;

                de = (DynamicEntity)context.PostEntityImages["Image"];
                //var assignee = (Moniker)context.InputParameters["Assignee"];
                var assignee = (SecurityPrincipal)context.InputParameters["Assignee"];
                OwnerProperty own = new OwnerProperty("ownerid", new Owner("systemuser", assignee.PrincipalId));
                de.Properties.Add(own);

                id = mon.Id;

                code = uds_eventtypecode.Assign;
            }
            else
            {
                return;
            }

            var ent = new Entity_
                {
                    System = system, 
                    Name = de.Name, 
                    Id = id.ToString()
                };

            foreach (Property prop in de.Properties)
            {
                AttributeMetadata amd = this.getAttrByName(emd, prop.Name);

                if (amd != null)
                {
                    switch (amd.AttributeType.Value)
                    {
                        case AttributeType.Boolean:
                            ent[prop.Name] = ((CrmBooleanProperty) prop).Value.Value;
                            break;
                        case AttributeType.CalendarRules:
                            break;
                        case AttributeType.Customer:
                            ent[prop.Name] = ((CustomerProperty)prop).Value.Value; 
                            break;
                        case AttributeType.DateTime:
                            ent[prop.Name] = ((CrmDateTimeProperty)prop).Value.UserTime.ToLocalTime();
                            break;
                        case AttributeType.Decimal:
                            ent[prop.Name] = ((CrmDecimalProperty)prop).Value.Value;
                            break;

                        //Удалил Double, т.к. его не было в свойствах AttributeType

                        case AttributeType.Integer:
                            ent[prop.Name] = ((CrmNumberProperty) prop).Value.Value;
                            break;
                        case AttributeType.Lookup:
                            ent[prop.Name] = ((LookupProperty)prop).Value.Value; 
                            break;
                        case AttributeType.Memo:
                            ent[prop.Name] = ((StringProperty)prop).Value;
                            break;
                        case AttributeType.Money:
                            ent[prop.Name] = ((CrmMoneyProperty)prop).Value.Value;
                            break;
                        case AttributeType.Owner:
                            ent[prop.Name] = ((OwnerProperty)prop).Value.Value; 
                            break;
                        case AttributeType.PartyList:
                            break;
                        case AttributeType.Picklist:
                            ent[prop.Name] = ((PicklistProperty) prop).Value.Value;
                            break;
                        case AttributeType.UniqueIdentifier:
                            ent[prop.Name] = ((KeyProperty)prop).Value.Value;
                            break;
                        case AttributeType.State:
                            ent[prop.Name] = ((StateProperty) prop).Value;
                            break;
                        case AttributeType.Status:
                            ent[prop.Name] = ((StatusProperty) prop).Value.Value;
                            break;
                        case AttributeType.String:
                            ent[prop.Name] = ((StringProperty) prop).Value;
                            break;
                        case AttributeType.Virtual:
                            break;
                    }
                }
            }

            Event evnt = new Event
            {
                Entity = ent,
                MessageName = context.MessageName,
                OccuredOn = DateTime.Now
            };

            Connector = new Dictionary<string, object>();
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            serializer.Serialize(sw, evnt);

            // create new object of uds_entity
            // OrganizationServiceContext orgContext = new OrganizationServiceContext(service);

            var uds_integrationevent = new DynamicEntity("uds_integrationevent");
            uds_integrationevent["uds_name"] = string.Format("{0} : {1}", evnt.MessageName, ent.Name);
            uds_integrationevent["uds_entity"] = ent.Name;
            uds_integrationevent["uds_entityid"] = ent.Id;
            uds_integrationevent["uds_event"] = sb.ToString();

            Picklist op;
            switch (code)
            {
                case uds_eventtypecode.Create:
                    op = new Picklist(752560000);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Update:
                    op = new Picklist(752560001);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Delete:
                    op = new Picklist(752560002);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
                case uds_eventtypecode.Assign:
                    op = new Picklist(752560003);
                    uds_integrationevent["uds_eventtypecode"] = op;
                    break;
            }

            service.Create(uds_integrationevent);
            
        }
    }
}
